// 1. 定义接口，用于类型安全
interface TmplConfig {
  tmplId: string;
  name: string;
}

// 2. 定义整个 subscriptionIds.json 文件的结构类型
type SubscriptionMessageIds = {
  [key: string]: TmplConfig;
};

// 3. 导入位于项目根目录的 subscriptionIds.json 文件
// 注意：路径是相对于当前文件 (src/utils/) 到根目录的相对路径
import { templateIds } from "../subscriptionIds";

// 4. 将导入的 JSON 对象断言为我们定义的类型，以获取类型提示和检查
const subscriptionMessageIds: SubscriptionMessageIds = templateIds;

// 5. 根据导入的 JSON 对象的键动态生成 SubscriptionKey 类型
// 这样在调用 subscriptionManager 时就能获得智能提示和类型检查
export type SubscriptionKey = keyof typeof subscriptionMessageIds;

// 6. 定义订阅选项接口
interface SubscriptionOptions {
  /**
   * 是否在所有订阅成功时显示成功提示 (wx.showToast)。
   * 默认为 false (不显示)，因为大部分情况下成功订阅不需要频繁打扰用户。
   * 如果有部分失败，即使设置为 true，也会优先显示失败提示。
   */
  showSuccessToast?: boolean;

  /**
   * 是否为“重要”消息。
   * 如果设置为 true，在用户拒绝订阅时，会弹出一个 Modal 引导用户前往设置页开启。
   * 默认为 false (只显示 Toast)。
   */
  isCrucial?: boolean;
}

/**
 * 消息订阅管理器
 * 统一处理微信小程序的订阅消息请求和用户反馈。
 *
 * @param keys 订阅消息的key数组，对应 project_root/subscriptionIds.json 中的键名。
 * @param options 订阅选项，可控制成功提示显示和重要消息的弹窗处理。
 *
 * 示例：
 * subscriptionManager(['orderStatus', 'newPromotion'], { showSuccessToast: true });
 * subscriptionManager(['importantNotice'], { isCrucial: true });
 */
export const subscriptionManager = async (
  keys: SubscriptionKey[],
  options: SubscriptionOptions = {}
): Promise<void> => {
  const { showSuccessToast = false, isCrucial = false } = options;

  // 1. 获取要订阅的模板ID和对应的名称
  const tmplIdsToSubscribe: string[] = [];
  const tmplIdToNameMap = new Map<string, string>(); // 用于显示友好的消息名称

  for (const key of keys) {
    const config = subscriptionMessageIds[key];
    if (config && config.tmplId) {
      tmplIdsToSubscribe.push(config.tmplId);
      tmplIdToNameMap.set(config.tmplId, config.name);
    } else {
      console.warn(
        `[SubscriptionManager] 未找到 key 为 "${key}" 的订阅消息配置或 tmplId。`
      );
    }
  }

  if (tmplIdsToSubscribe.length === 0) {
    console.warn("[SubscriptionManager] 没有有效的订阅消息ID可供订阅。");
    wx.showToast({
      title: "没有可订阅的消息",
      icon: "none",
      duration: 2000,
    });
    return;
  }

  try {
    // 2. 调用微信订阅消息API
    const res = await wx.requestSubscribeMessage({
      tmplIds: tmplIdsToSubscribe,
    });

    const acceptedNames: string[] = [];
    const rejectedNames: string[] = [];
    let isPartiallyFailed = false;

    // 3. 处理订阅结果
    for (const tmplId of tmplIdsToSubscribe) {
      const status = res[tmplId];
      const messageName = tmplIdToNameMap.get(tmplId) || "未知消息";

      if (status === "accept") {
        acceptedNames.push(messageName);
      } else if (status === "reject" || status === "ban") {
        // 'reject': 用户拒绝了一次性订阅
        // 'ban': 用户在小程序设置中拒绝了该模板或全部模板，或被后台封禁
        rejectedNames.push(messageName);
        isPartiallyFailed = true;
      }
      // 对于其他未知状态，例如 'confirm' 或小程序未来可能新增的状态，目前不做特殊处理
    }

    // 4. 根据结果给出用户提示
    if (isPartiallyFailed || rejectedNames.length > 0) {
      const failMsg = `以下消息订阅失败：${rejectedNames.join(
        "、"
      )}。您可能无法实时收到这些信息。`;

      if (isCrucial) {
        // 对于重要消息，使用 Modal 引导用户开启
        wx.showModal({
          title: "订阅失败",
          content: `${failMsg}\n\n为确保您能及时收到重要通知，请点击“去设置”在小程序设置页中开启。`,
          confirmText: "去设置",
          cancelText: "取消",
          success: (modalRes) => {
            if (modalRes.confirm) {
              wx.openSetting({
                withSubscriptions: true, // 微信新版本建议带上此参数，直接跳转到订阅消息设置
                success: () => {
                  console.log("用户已跳转到设置页");
                },
                fail: (err) => {
                  console.error("跳转设置页失败", err);
                  wx.showToast({
                    title: "跳转设置页失败，请手动前往",
                    icon: "none",
                    duration: 2000,
                  });
                },
              });
            } else if (modalRes.cancel) {
              wx.showToast({
                title: "订阅失败，请注意消息通知",
                icon: "none",
                duration: 2500,
              });
            }
          },
        });
      } else {
        // 非重要消息，使用 Toast 提示
        wx.showToast({
          title: failMsg,
          icon: "none",
          duration: 3500, // 失败信息显示时间长一点
        });
      }
    } else if (acceptedNames.length > 0 && showSuccessToast) {
      // 所有订阅都成功，且设置了显示成功Toast
      wx.showToast({
        title: "消息订阅成功！",
        icon: "success",
        duration: 1500,
      });
    }
  } catch (err: any) {
    // 5. 处理API调用失败的情况 (例如用户拒绝整个订阅请求，或网络错误)
    let errorMessage = "消息订阅失败，请稍后再试。";
    let showSettingGuidance = false;

    // 根据错误码或错误信息判断失败原因
    if (err.errCode === 20004 || err.errMsg.includes("scope unauthorized")) {
      // 用户在设置中拒绝了订阅消息总开关 (20004: 用户拒绝订阅消息)
      errorMessage = "消息订阅权限被拒绝，请前往小程序设置页开启。";
      showSettingGuidance = true;
    } else if (err.errCode === 20001) {
      // 用户点击了订阅弹窗的“取消”按钮 (20001: 用户取消订阅消息)
      errorMessage = "您取消了消息订阅，可能无法及时收到重要通知。";
      // 这种情况下，如果isCrucial，仍然引导用户
      showSettingGuidance = isCrucial;
    } else {
      console.error("[SubscriptionManager] 订阅消息API调用失败：", err);
    }

    if (showSettingGuidance) {
      wx.showModal({
        title: "订阅失败",
        content: `${errorMessage}\n\n点击“去设置”在小程序设置页中开启。`,
        confirmText: "去设置",
        cancelText: "取消",
        success: (modalRes) => {
          if (modalRes.confirm) {
            wx.openSetting({
              withSubscriptions: true,
              success: () => {
                console.log("用户已跳转到设置页");
              },
              fail: (e) => {
                console.error("跳转设置页失败", e);
                wx.showToast({
                  title: "跳转设置页失败，请手动前往",
                  icon: "none",
                  duration: 2000,
                });
              },
            });
          } else if (modalRes.cancel) {
            wx.showToast({
              title: "订阅失败，请注意消息通知",
              icon: "none",
              duration: 2500,
            });
          }
        },
      });
    } else {
      wx.showToast({
        title: errorMessage,
        icon: "none",
        duration: 2500,
      });
    }
  }
};
